#include "Camera.h"


Camera::Camera() :	dV( XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f)),
					dU( XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f)),
					eye(XMVectorSet(0.0f, 4.0f, -10.0f, 0.0f)),
					view(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f)),
					up(XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f)),
					forward(XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f)),
					strafeRight(XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f)),
					heading(0),
					pitch(0),
					movementSpeed(1)
{
	//set matrices to identity
	viewMatrix = XMMatrixIdentity();
	projectionMatrix = XMMatrixIdentity();

	//initialize movement toggles
	movementToggles[0] = 0;
	movementToggles[1] = 0;
	movementToggles[2] = 0;
	movementToggles[3] = 0;
}


Camera::~Camera()
{
}

void Camera::setPerspectiveProjectionLH(float FOV, float aspectRatio, float zNear, float zFar)
{
	//convert FOV from degrees to radians
	FOV = FOV * (float)DEG_TO_RAD;

	projectionMatrix = XMMatrixPerspectiveFovLH(XM_PIDIV4, aspectRatio, zNear, zFar);	
}

/*******************************************************************
* update view from Camera heading and pitch
********************************************************************/
void Camera::updateView()
{
	//create rotation matrix
	rotationMatrix = XMMatrixRotationRollPitchYaw(pitch, heading, 0);

	//create new view and up vectors
	view = XMVector3TransformCoord(dV, rotationMatrix);
	up = XMVector3TransformCoord(dU, rotationMatrix);

	//create new forward and strafe vectors
	forward = XMVector3Normalize(view);
	strafeRight = XMVector3Cross(up, view);
	strafeRight = XMVector3Normalize(strafeRight);

	//take into account eye position
	view = eye + view;

	//update view matrix
	viewMatrix = XMMatrixLookAtLH(eye, view, up);
}

void Camera::setPositionAndView(float x, float y, float z, float hDeg, float pDeg)
{
	//set eye coordinates
	eye = XMVectorSet(x, y, z, 0.0f);

	//set heading and pitch
	adjustHeadingPitch(hDeg * (float)DEG_TO_RAD, pDeg * (float)DEG_TO_RAD);

	//update view 
	updateView();
}

void Camera::adjustHeadingPitch(float hRad, float pRad)
{
	heading += hRad;
	pitch += pRad;

	//value clamping - keep heading and pitch between 0 and 2 pi
	if (heading > TWO_PI) heading -= (float)TWO_PI;
	else if (heading < 0) heading = (float)TWO_PI + heading;

	if (pitch > TWO_PI) pitch -= (float)TWO_PI;
	else if (pitch < 0) pitch = (float)TWO_PI + pitch;
}

void Camera::setMovementToggle(int i, int v)
{
	movementToggles[i] = v;
}

void Camera::setMovementSpeed(float s)
{
	movementSpeed = s;
}

void Camera::update()
{
	//get current elapsed time
	double t = camTimer.getElapsedTimeSeconds();

	//update position - 1.5 unit per second
	eye += (float)t * (movementToggles[0] + movementToggles[1]) * movementSpeed * forward +
		(float)t * (movementToggles[2] + movementToggles[3]) * movementSpeed * strafeRight;

	//update view
	updateView();

	//reset timer
	camTimer.reset();
}